﻿namespace Jhong.Data.Core.Infrastructure
{
    using System;
    using System.Globalization;

    internal class DataConverter<T>
    {
        private static readonly Converter<object, T> _converter = CreateConvert<T>();

        public static T Convert(object value)
        {
            return _converter(value);
        }

        private static Converter<object, T> CreateConvert<T>()
        {
            var type = typeof(T);
            if (type.IsEnum) return (x) =>
            {
                var str = x as string;
                if (string.IsNullOrWhiteSpace(str)) return (T)Enum.ToObject(type, x);
                return (T)Enum.Parse(type, str);
            };
            else if (CheckType(type)) return (x) =>
            {
                try
                {
                    return (T)x;
                }
                catch
                {
                    return (T)(x as IConvertible).ToType(type, CultureInfo.InvariantCulture);
                }
            };
            else if (type.Name.Equals("Object")||type.Name.Equals("Guid")) return (x) =>
            {
                return (T)x;
            };
            else return (x) =>
            {
                throw new InvalidCastException(string.Format("无法将{0}类型的值转化为{1}类型", x.GetType().Name, type.Name));
            };
        }

        private static bool CheckType(Type type)
        {
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Boolean:
                case TypeCode.Byte:
                case TypeCode.Char:
                case TypeCode.DateTime:
                case TypeCode.Decimal:
                case TypeCode.Double:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.SByte:
                case TypeCode.Single:
                case TypeCode.String:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                    return true;
                default: return false;
            }
        }
    }
}